﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using Bookvar.ApplicationModel;
using Bookvar.ObjectModel;
using Bookvar.ServiceModel;
using Bookvar.UI;
using Bookvar.UI.Commands;

namespace BookvarWpf
{
    /// <summary>
    /// Interaction logic for Presentation.xaml
    /// </summary>
    public partial class Presentation
    {
        private const double DesiredZoomValue = 2;
        private const double ActiveTopicOpacity = 1.0;
        private const double InactiveTopicOpacity = 0.5;
        private static readonly IList<TopicContentPresenter> presentationOrder = new List<TopicContentPresenter>();
        private static int currentTopicIndex = -1;

        private static IViewService ViewService
        {
            get { return BookvarApplication.Current.ServiceLayer.GetService<IViewService>(); }
        }

        public Presentation()
        {
            InitializeComponent();

            Loaded += Presentation_Loaded;

            CommandBinding nextPresentationTopicBinding =
                new CommandBinding(BookvarUICommands.NextPresentationTopic, NextPresentationTopicCommandExecuted);
            CommandBindings.Add(nextPresentationTopicBinding);

            CommandBinding previousPresentationTopicBinding =
                new CommandBinding(BookvarUICommands.PreviousPresentationTopic,
                                    PreviousPresentationTopicCommandExecuted);
            CommandBindings.Add(previousPresentationTopicBinding);

            CommandBinding exitPresentationModeBinding =
                new CommandBinding(BookvarUICommands.ExitPresentationMode,
                                    ExitPresentationModeCommandExecuted);
            CommandBindings.Add(exitPresentationModeBinding);


            KeyBinding exitPresentationModeKeyBinding = new KeyBinding(BookvarUICommands.ExitPresentationMode, Key.Escape, ModifierKeys.None);
            exitPresentationModeKeyBinding.CommandTarget = this;
            InputBindings.Add(exitPresentationModeKeyBinding);

            BookvarApplication.Current.Navigating += OnNavigating;
        }

        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            if (e.Key == Key.PageUp)
            {
                BookvarUICommands.PreviousPresentationTopic.Execute(null, this);
                e.Handled = true;
            }
            else if (e.Key == Key.Next)
            {
                BookvarUICommands.NextPresentationTopic.Execute(null, this);
                e.Handled = true;
            }
            base.OnPreviewKeyDown(e);
        }

        private void OnNavigating(object sender, NavigatingCancelEventArgs e)
        {
            if (IsLoaded)
            {
                BookvarApplication.Current.ServiceLayer.RemoveService(typeof(IViewService));
                BookvarApplication.Current.Navigating -= OnNavigating;
            }
        }

        private void Presentation_Loaded(object sender, RoutedEventArgs e)
        {
            Application.Current.MainWindow.WindowStyle = WindowStyle.None;
            Application.Current.MainWindow.WindowState = WindowState.Maximized;

            InitPresentation();
            BookvarApplication.Current.ServiceLayer.AddService<IViewService>(
                new ViewService(mindMap, zoomer, scrollViewer));
        }

        public MindMap Mindmap
        {
            get { return mindMap.Mindmap; }
            set { mindMap.Mindmap = value; }
        }

        public Uri Skin
        {
            get { return mindMap.Skin; }
            set { mindMap.Skin = value; }
        }

        private void NextPresentationTopicCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (currentTopicIndex < (presentationOrder.Count - 1))
            {
                presentationOrder[currentTopicIndex].Opacity = InactiveTopicOpacity;
                currentTopicIndex++;
                FocusTopic(currentTopicIndex);
            }
        }

        private void PreviousPresentationTopicCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (currentTopicIndex > 0)
            {
                presentationOrder[currentTopicIndex].Opacity = InactiveTopicOpacity;
                currentTopicIndex--;
                FocusTopic(currentTopicIndex);
            }
        }


        private void ExitPresentationModeCommandExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            NavigationService.GoBack();
        }

        private void InitPresentation()
        {
            BreadthFirstPresentationOrder(presentationOrder, mindMap.MainTopicPresenter);
            if (presentationOrder.Count > 0)
            {
                currentTopicIndex = 0;
                FocusTopic(currentTopicIndex);
            }


            DoubleAnimation zoomerAnimation = new DoubleAnimation(
                zoomer.Value,
                DesiredZoomValue,
                new Duration(TimeSpan.FromSeconds(2)), FillBehavior.Stop);

            zoomerAnimation.DecelerationRatio = 0.7;
            zoomerAnimation.Completed += delegate { zoomer.Value = DesiredZoomValue; };
            zoomer.BeginAnimation(RangeBase.ValueProperty, zoomerAnimation);
        }

        //TODO: Create also: DeepFirstPresentationOrder
        private static void BreadthFirstPresentationOrder(ICollection<TopicContentPresenter> presentationOrder,
                                                           TopicContentPresenter parentTopicPresenter)
        {
            presentationOrder.Add(parentTopicPresenter);
            parentTopicPresenter.Opacity = InactiveTopicOpacity;
            if (!(parentTopicPresenter.Topic is MainTopic)) //Do not call collapse on main topic
            {
                parentTopicPresenter.CollapseChildren();
            }

            foreach (TopicContentPresenter topicPresenter in parentTopicPresenter.Children)
            {
                BreadthFirstPresentationOrder(presentationOrder, topicPresenter);
            }
        }

        private void FocusTopic(int topicIndex)
        {
            TopicContentPresenter currentTopicPresenter = presentationOrder[topicIndex];
            if (ViewService != null)
            {
                ViewService.CenterTopic(currentTopicPresenter.Topic, true);
            }

            mindMap.SelectedTopic = currentTopicPresenter.Topic;
            currentTopicPresenter.Opacity = ActiveTopicOpacity;
            currentTopicPresenter.ExpandChildren();
        }
    }
}